/*
 * This file is a part of the SWFer project.
 *
 * Copyright (C) 2012 Michael Bradshaw <mjbshaw@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place, Suite 330, Boston, MA 02111-1307 USA
 *
 */

#ifndef BYTEWRITER_HPP
#define BYTEWRITER_HPP

#include "BasicTypes.hpp"
#include "TagHeader.hpp"
#include "SwfHeader.hpp"
#include "Packet.hpp"

#include <ostream>
#include <string>
#include <vector>
#include <deque>

namespace swfer
{

class ByteWriter
{
public:
	ByteWriter(std::ostream& stream);

	// TODO: return bool based on stream validity?
	// TODO: test stream during reads for validity
    void write(char value);

    void write(int8_t value);
    void write(int16_t value);
    void write(int32_t value);

    void write(uint8_t value);
    void write(uint16_t value);
    void write(uint32_t value);

    void write(const Rect& value);

    void write(const Fixed16& value);
    void write(const Fixed32& value);

    void write(const TagHeader& value);
    void write(const SwfHeader& value);
	void write(const Packet& value);

	void write(const std::string& value);

	void write(const std::vector<char>& value);

    template <uint8_t N>
    void write(const BitField<N>& value)
	{
		uint32_t i = 1 << value.bits;
		while (i >>= 1)
		{
			bitField.push_back((value & i) != 0);
		}

		while (bitField.size() >= 8)
		{
			char c = 0;
			for (int shift = 7; shift >= 0; --shift)
			{
				c |= bitField.front() << shift;
				bitField.pop_front();
			}
			stream.put(c);
		}
	}

private:
	std::ostream& stream;

	std::deque<bool> bitField;

	void flushBitField();
};

}

#endif
